package com.example.myapp.models;

import com.example.myapp.event.EventHandler;
import com.example.myapp.event.GameEndEvent;
import com.example.myapp.players.Player;
import com.example.myapp.utils.StateAnalysis;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GameControl {

    private int currentPlayerId;
    private List<Player> players = new ArrayList<>();
    private List<Integer> playerIds = new ArrayList<>();
    private List<int[]> gameRecords = new ArrayList<>();
    private Game game;

    public int getCurrentPlayerId() {
        return currentPlayerId;
    }

    private void setCurrentPlayerId(int currentPlayer) {
        this.currentPlayerId = currentPlayer;
    }

    public boolean addPlayer(Player player) {
        if (players.size() > 0) {
            if (playerIds.contains(player.getFaction())) {
                return false;
            }
        }
        player.setGame(getGame());
        players.add(player);
        playerIds.add(player.getFaction());
        return true;
    }

    public boolean removePlayer(Player player) {
        if (players.size() > 0) {
            for (Iterator it = playerIds.iterator(), it2 = players.iterator(); it.hasNext();) {
                Integer in = (Integer) it.next();
                it2.next();
                if (in == player.getFaction()) {
                    it.remove();
                    it2.remove();
                }
            }
        }
        return false;
    }

    private int getCurrentPlayerIndex() {
        for (int i = 0; i < playerIds.size(); i++) {
            if (playerIds.get(i) == currentPlayerId) {
                return i;
            }
        }
        return -1;
    }

    private Player getCurrentPlayer() {
        int id = getCurrentPlayerIndex();
        if (id != -1) {
            return players.get(id);
        } else {
            return null;
        }
    }

    public void beginGame() {
        selectPlayer(0);
        while (true) {
            //Game main logic: wait for next input
            int[] action;
            Player currentPlayer = getCurrentPlayer();
            int[] stateMatrix = game.getStateMatrix();
            int[] step = new int[Game.MATRIX_WIDTH * Game.MATRIX_WIDTH + 3];
            System.arraycopy(stateMatrix, 0, step, 0, stateMatrix.length);
            if (currentPlayer != null) {
                action = currentPlayer.getNextStep(game.getStateMatrix(), getCurrentPlayerId());
                game.putPiece(currentPlayer.getFaction(), action[0], action[1]);
                step[step.length - 3] = action[0];
                step[step.length - 2] = action[1];
                step[step.length - 1] = currentPlayer.getFaction();
            }
            gameRecords.add(step);
            if (endGameCheck()) {
                endGame();
                break;
            }
            moveToNextPlayer();
        }
    }

    private boolean endGameCheck() {
        int empty = StateAnalysis.calculateEmptySlots(game);
        if (empty == 0) {
            return true;
        }
        int[] factionCounts = new int[players.size()];
        for (int i = 0; i < players.size(); i++) {
            factionCounts[i] = StateAnalysis.getCountByFaction(getGame(), players.get(i).getFaction());
            if (factionCounts[i] == 0) {
                return true;
            }
        }
        return false;
    }

    public void endGame() {
        int p1 = StateAnalysis.getCountByFaction(game, 1);
        int p2 = StateAnalysis.getCountByFaction(game, 2);
        int result = p1 == p2 ? 0 : p1 < p2 ? -1 : 1;
        //finish records
        for (int[] record : gameRecords) {
            int src = record[Game.MATRIX_WIDTH * Game.MATRIX_WIDTH + 2];
            record[record.length - 1] = src == 1 ? result : -result;
        }
        //calculate result
        String resultString = "Player 1(Red): " + StateAnalysis.getCountByFaction(game, 1) + " Player 2(Green): " + StateAnalysis.getCountByFaction(game, 2);
        GameEndEvent event = new GameEndEvent(this, resultString);
        EventHandler.handleEvent(event);
        System.out.println(resultString);
    }

    private void moveToNextPlayer() {
        int index = getCurrentPlayerIndex() + 1;
        if (index == 0) {
            //empty player list
            return;
        } else if (index == players.size()) {
            index = 0;
        }
        selectPlayer(index);
    }

    private void selectPlayer(int index) {
        setCurrentPlayerId(playerIds.get(index));
    }

    public Game getGame() {
        return game;
    }

    public void setGame(Game game) {
        this.game = game;
    }
}
